﻿using System;
using System.Threading;

namespace Qplus.Infrastructure
{
    public class AsyncResultNoResult : IAsyncResult
    {
        private readonly AsyncCallback _asyncCallback;//异步请求的返回方法
        private readonly object _asyncState;//异步请求的对象

        private ManualResetEvent _asyncWaitHandle;//线程阻塞

        private Exception _exception;//操作异常

        private int _completedState;//完成状态
        private const int StateCompletedAsynchronously = 2;//异步完成
        private const int StateCompletedSynchronously = 1;//同步完成
        private const int StatePending = 0;
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="asyncCallback">异步返回方法</param>
        /// <param name="state">异步调用对象</param>
        public AsyncResultNoResult(AsyncCallback asyncCallback, object state)
        {
            this._asyncCallback = asyncCallback;
            this._asyncState = state;
        }
        /// <summary>
        /// 结束任务
        /// </summary>
        public void EndInvoke()
        {
            // This method assumes that only 1 thread calls EndInvoke 
            // for this object
            if (!this.IsCompleted)//任务未完成
            {
                // If the operation isn't done, wait for it
                this.AsyncWaitHandle.WaitOne();
                this.AsyncWaitHandle.Close();
                this._asyncWaitHandle = null; // Allow early GC
            }
            if (this._exception != null)
            {
                RethrowException(this._exception);
            }
        }

        private static void RethrowException(Exception ex)
        {
            throw ex;
        }

        public void SetAsCompleted(Exception exception, bool completedSynchronously)
        {
            // Passing null for exception means no error occurred. 
            // This is the common case
            this._exception = exception;
            // The m_CompletedState field MUST be set prior calling the callback
            if (Interlocked.Exchange(ref this._completedState, completedSynchronously ? 1 : 2) != 0)
            {

                throw new InvalidOperationException("You can set a result only once", exception);
            }
            if (this._asyncWaitHandle != null)
            {// If the event exists, set it
                this._asyncWaitHandle.Set();
            }
            if (this._asyncCallback != null)
            {// If a callback method was set, call it
                this._asyncCallback(this);//调用异步请求的返回方法
            }
        }
        /// <summary>
        /// 放弃异步请求的对象
        /// </summary>
        public object AsyncState
        {
            get
            {
                return this._asyncState;
            }
        }

        public WaitHandle AsyncWaitHandle
        {
            get
            {

                if (this._asyncWaitHandle == null)
                {
                    bool isCompleted = this.IsCompleted;
                    ManualResetEvent event2 = new ManualResetEvent(isCompleted);
                    if (Interlocked.CompareExchange<ManualResetEvent>(ref this._asyncWaitHandle, event2, null) != null)
                    {
                        // Another thread created this object's event; dispose 
                        // the event we just created
                        event2.Close();
                    }
                    else if (!isCompleted && this.IsCompleted)
                    {
                        // If the operation wasn't done when we created 
                        // the event but now it is done, set the event
                        //如果操作已经完成则释放阻塞
                        this._asyncWaitHandle.Set();
                    }
                }
                return this._asyncWaitHandle;
            }
        }
        //同步操作是否已经完成
        public bool CompletedSynchronously
        {
            get
            {
                return (this._completedState == 1);
            }
        }
        //是否已经完成
        public bool IsCompleted
        {
            get
            {
                return (this._completedState != 0);
            }
        }
    }
}
